package com.common.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JwtToken生成的工具类
 * JWT token的格式：header.payload.signature
 * header的格式（算法、token的类型）：
 * {"alg": "HS512","typ": "JWT"}
 * payload的格式（用户名、创建时间、生成时间）：
 * {"sub":"wang","created":1489079981393,"exp":1489684781}
 * signature的生成算法：
 * HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
 */
public class JWTUtil {

    /** token秘钥，请勿泄露，请勿随便修改 */
    private static final String  SECRET = "209A35F488AE684F";
    private static final String  ISSUER = "209A35F488AE684F";
    private static final String Subbject = "fibocom";
    private static final Long expiration = Long.valueOf(600 * 1);  //1个小时失效
    //private static final Long expiration = Long.valueOf(20);

    private static final String Account = "Account";

    public static String tokenFromAccount(String account){

        Map<String, String> newMap = new HashMap<>();
        newMap.put(Account, account);
        return generateToken(newMap);
    }
    /**
     * @Method: 根据参数  生成token
     * @return:
     * @Author: paycloud110
     */
    public static String generateToken(Map<String, String> claims){
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTCreator.Builder builder = JWT.create()
                .withIssuer(ISSUER)
                .withSubject(Subbject)
                .withIssuedAt(new Date()) // 生成时间
                .withExpiresAt(generateExpirationDate()); // 设置过期时间
            claims.forEach((k, v)->
                builder.withClaim(k, v)
            );
            return builder.sign(algorithm);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Method: 根据token获取对应的信息
     * @return: exp=null, iat=null 如果从jwt.getClaims()则获取不到过期和生成时间，需要从
     *     jwt.getExpiresAt() jwt.getIssuedAt()
     * @Author: paycloud110
     */
    public static Map<String, String> getMsgFromToken(String token)  {
        Algorithm algorithm = null;
        try {
            algorithm = Algorithm.HMAC256(SECRET);
        } catch (IllegalArgumentException e) {
            return null;
        }
        JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
        DecodedJWT jwt =  verifier.verify(token);
        Map<String, String> resultMap = new HashMap<>();
        Map<String, Claim> map = jwt.getClaims();
        map.forEach((k,v) ->
            resultMap.put(k, v.asString())
        );
        return resultMap;
    }

    /**
     * 用于获取jwt对象
     * @param token
     * @return
     */
    public static DecodedJWT getDecodedJWTFromToken(String token)  {
        Algorithm algorithm = null;
        try {
            algorithm = Algorithm.HMAC256(SECRET);
        } catch (IllegalArgumentException e) {
            return null;
        }
        JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
        DecodedJWT jwt =  verifier.verify(token);
        return jwt;
    }

    /**
     * 生成token的过期时间
     */
    private static Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    /**
     * 从token中获取登录用户名
     */
    public static String getUserNameFromToken(String token) {
        String username;
        try {
            Map claims = getMsgFromToken(token);
            username =  (String) claims.get(Account);
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param
     */
    public static boolean validateToken(String token, String user) {
        String username = getUserNameFromToken(token);
        return username.equals(user) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    public static boolean isTokenExpired(String token) {
        DecodedJWT jwt = getDecodedJWTFromToken(token);
        return jwt.getExpiresAt().before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    public static Date getExpiredDateFromToken(String token) {
        DecodedJWT jwt = getDecodedJWTFromToken(token);
        return jwt.getExpiresAt();
    }

    /**
     * 判断token是否可以被刷新
     */
    public static boolean canRefresh(String token) {
        return !isTokenExpired(token);
    }

    /**
     * 刷新token
     */
    public static String refreshToken(String token) {
        Map claims = getMsgFromToken(token);
        return generateToken(claims);
    }

    public static void main(String[] args) {
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmaWJvY29tIiwiQWNjb3VudCI6ImFkbWluIiwiaXNzIjoiMjA5QTM1RjQ4OEFFNjg0RiJ9.WXt5viECamdV7wttzr4ODu-e6GhGTn9X7OXw0TUfMPk";
        // System.out.println(canRefresh(token));
        System.out.println(getUserNameFromToken(token));
        //System.out.println(refreshToken(token));
        System.out.println(getExpiredDateFromToken(token));
    }
}
